package liu.de.service;

import liu.de.dto.TaskDTO;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * @author liude
 */
@Service
@Slf4j
public class AsyncTaskService {

    private final RedissonClient redissonClient;

    @Autowired
    public AsyncTaskService(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }

    @Async
    @Retryable(maxAttempts = 2, backoff = @Backoff(delay = 2000))
    public void submit(TaskDTO taskDTO) {
        RLock lock = redissonClient.getLock("task_lock_" + taskDTO.getKey());

        boolean getLock = false;

        try {
            getLock = lock.tryLock(1, 20, TimeUnit.SECONDS);
        } catch (InterruptedException ignored) {
        }

        if (!getLock) {
            log.info("task is duplicated, do not submit, task={}", taskDTO);
            return;
        }

        try {
            execute(taskDTO);
        } catch (Exception e) {
//            log.error("", e);
            throw e;
        } finally {
            lock.unlock();
        }
    }

    private void execute(TaskDTO taskDTO) {
        log.info("executing task {}", taskDTO);


        try {
            TimeUnit.SECONDS.sleep(taskDTO.getTimeInSeconds());
        } catch (InterruptedException ignored) {
        }


//        if (new Random().nextBoolean()) {
//            log.info("random failure {}", taskDTO);
//            throw new RuntimeException("execute failed");
//        }

        log.info("task is done {}", taskDTO);
    }

}
